package net.wanderinghorse.jsonmessage;

/**
 * This is the ServletResponse equivalent of AbstractResponseHandler.
 *
 * It supports subclasses which require, or optionally support, an incoming
 * HttpServletRequest object. The intention is to help support handlers which
 * use the application's HTTP session and/or cookies.
 */
public abstract class AbstractRequestHandlerServlet extends AbstractRequestHandler implements RequestHandlerServlet {
    private boolean requireServlet;

    /**
     * Initializes this object.
     * @param requireServletRequest If true then processRequest() calls which
     * pass in a null HttpServletRequest object will be allowed, otherwise
     * they will cause an exception.
     */
    protected AbstractRequestHandlerServlet( boolean requireServletRequest ) {
        super();
        requireServlet = requireServletRequest;
    }

    /**
     * Specifies whether this object can be used without an accompanying
     * HttpServletRequest object.
     *
     * TODO: consider moving this into the base ServletResponseHandler interface.
     *
     * @return True if this handler _requires_ an incoming HttpServletRequest
     * in order to function, else false.
     */
    public final boolean getRequiresServlet() {
        return this.requireServlet;
    }

    /**
     * The default response resultCode used by this class' internal error handling.
     */
    public static final int DEFAULT_ERROR_RC = 1;
    /**
     * Must be overridden by subclasses and behave as described for
     * ResponseHandler.processResponse().
     *
     * If getRequiresServlet() returns false and processResponse() is passed
     * null servlet value, this member will never be called - instead an error is generated
     * explaining the lack of a servlet. If getRequiresServlet() returns true then this function
     * may be passed a null value for hreq.
     *
     * @param hreq The inbound HTTP request info from which the req argument originated. Whether or not
     * they may legally be null is up to the implementation.
     * @param req The request object which caused the fetching of the response.
     * @param resp The response object to populate.
     * @throws Exception Implementations may throw arbitrary exceptions.
     * */
    protected abstract void doProcessResponse(ServletInfo hreq, final Request req, final Response resp) throws Exception;

    /**
     * Equivalent to setErrorState( resp, rc, ex.getMessage() ).
     *
     * @param resp The response to modify.
     * @param rc The error code. If it is 0 then DEFAULT_ERROR_RC is used.
     * @param ex The exception to pull the message string from.
     */
    protected void setErrorState( Response resp, int rc, Exception ex ) {
        setErrorState( resp, rc, ex.getMessage() );
    }

    /**
     * A convenience method to set resp's resultCode and resultText, and
     * clears its payload.
     *
     * If rc is 0 then DEFAULT_ERROR_RC is used.
     *
     * @param resp The response to modify.
     * @param rc The responseCode value.
     * @param msg The responseText string.
     */
    protected void setErrorState( Response resp, int rc, String msg ) {
        resp.setResultCode( (0==rc) ? DEFAULT_ERROR_RC : rc );
        resp.setResultText( msg );
        resp.setPayload( null );
    }
    /**
     * Sets up resp's "responseTo" and "type" properties to the id resp.
     * type of req, then calls the protected doProcessResponse() to do
     * any type-specific handling. If doProcessResponse() throws then
     * resp's payload is removed and resp is populated with information
     * for reporting the error.
     *
     * If getRequiresServlet() is true and hreq is null then this function
     * will throw a IllegalArgumentException, which the dispatcher should then
     * wrap up as an error response object.
     *
     * @param hreq The inbound HTTP request info from which the req argument originated. Whether or not
     * they may legally be null is up to the implementation.
     * @param req The request object which caused the fetching of the response.
     * @param resp The response object to populate.
     * @throws IllegalArgumentException If getRequiresServlet() is true and hreq is null.
     */
    public final void processResponse(ServletInfo hreq, final Request req, final Response resp) throws Exception {
        if( requireServlet && (null == hreq) ) {
            throw new IllegalArgumentException("This handler requires a HttpServletRequest in order to function!");
        }
        resp.setRequestId( req.getId() );
        resp.setType( req.getType() );
        try {
            this.doProcessResponse( hreq, req, resp);
        }
        catch( Exception ex ) {
            setErrorState( resp, DEFAULT_ERROR_RC, ex );
        }
    }

    /**
     * Equivalent to processResponse(null, resp, req). If getRequiresServlet()
     * returns true then this function will throw a runtime exception.
     *
     * @param req The request object which caused the fetching of the response.
     * @param resp The response object to populate.
     */
    protected final/*???*/ void doProcessResponse(final Request req, final Response resp) throws Exception{
        processResponse( null, req, resp);
    }

}
